#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <sys/time.h>  
#include <time.h> 
#include "cssl.h"

void SIG_handle(int s);

void usage (char *name)
{
    fprintf (stdout, "Usage: %s SERIAL_FILE_NAME DATABASE_NAME TITLE\n", name);
    fprintf (stdout, "  SERIAL_FILE_NAME  --Serial port file name to read.\n");
    fprintf (stdout, "  DATABASE_NAME     --Database file name to save log.\n");
    fprintf (stdout, "  TITLE             --Title of log.\n");
}
/*#define     DEVICE   "/dev/tty"*/

int tty = 0;
struct termios newt, oldt;

void init_tty (void)
{
    tty = open("/dev/tty", O_RDONLY);
    
    //获取终端属性
    tcgetattr(tty, &oldt);
    newt = oldt;
    /*//设置字符不缓冲且不回显*/
    /*newt.c_lflag &= ~( ICANON);*/
    //设置字符不缓冲且不回显
    newt.c_lflag &= ~( ICANON | ECHO );
    tcsetattr(tty, TCSANOW, &newt);

}

/*******************************************************************************
 * Function:      keyboard_event_thread()
 * Description:   串口收到数据后回调函数
 * Calls:         None
 * Called By:     cssl库
 * Input:         id      --传入ID
 *                buffer  --数据缓冲区
 *                len     --数据长度
 * Return:        void
 * Others:        None
 ******************************************************************************/
void *keyboard_event_thread(void *arg) 
{
    int i = 0;
    char buffer[512] = {0};
    char ch;
    cssl_t *serial = (cssl_t *)arg;
    /*int i = 0;*/
    /*init_tty();*/
    putchar ('>');
    fflush(stdout);

    while (1)
    {
        read(tty, &ch, 1);
        /*putchar (ch);*/
        if (ch == '\n' || i >= 512)
        {
             i = 0;
             cssl_putchar(serial, '\r');
        }
        cssl_putchar(serial, ch);
        buffer[i++] = ch;
    }
}


typedef enum _log_type
{
    LOG_TYPE_NOMAL,
    LOG_TYPE_TIMEOUT,
}log_type_t;



int save_log(FILE *logfile, char *title, char *msg, int len, int type)
{
    struct timeval tv;
    char *typestr = NULL;

    if (len == 0) return -1;

    gettimeofday(&tv,NULL);

    switch (type)
    {
        case LOG_TYPE_NOMAL :
            typestr = "NORMAL";
            break;
        case LOG_TYPE_TIMEOUT :
            typestr = "TIMEOUT";
            break;
        default :
            typestr = "NORMAL";
            break;
    }

    fprintf (logfile, "%s|%010u%06u|%04d|%07s|%s\n%",title, tv.tv_sec,tv.tv_usec, len, typestr ,msg);
    fflush (logfile);
}

//串口采集主循环
int loop(cssl_t *serial, FILE *of, char *title)
{
    int data;
    int log_type;
#define     LOOP_BUFFER_LEN 512
    char buffer[LOOP_BUFFER_LEN] = {0};
    int i = 0;

    fd_set rfds;
    struct timeval setv;
    int retval;
    int len;

    save_log (of, title, "[开始串口监听]", strlen("[开始串口监听]"), LOG_TYPE_NOMAL);
    while (1)
    {
        do
        {
            log_type = LOG_TYPE_NOMAL; //正常日志
            /* Watch serial (fd ) to see when it has input. */
            FD_ZERO(&rfds);
            FD_SET(serial->fd, &rfds);
            /* Wait up to five seconds. */
            setv.tv_sec = 5;
            setv.tv_usec = 0;
            retval = select(serial->fd+1, &rfds, NULL, NULL, &setv);
            /* Don’t rely on the value of tv now! */

            if (retval == -1)
                perror("select()");
            else if (retval)    //没有超时的情况
            {
                if (i >= LOOP_BUFFER_LEN - 2)  //缓冲区满
                {
                    break;
                }

                data = cssl_getchar(serial); //读取字符

                if (data == '\r') continue;
                else if (data == '\n' 
                        || data == 0x1a
                        || data == 0x1b
                        )
                {
                    break;
                }
                else if (data == '>')
                {
                    buffer[i++] = data;
                    break;
                }
                buffer[i++] = data;
            }
            else   //超时没收到数据
            {
                log_type = LOG_TYPE_TIMEOUT; //超时日志
                len = strlen(buffer);
                if (len != 0)
                {
                    break;
                }
            }
        }
        while(1);
        /*{++++++++++++符合条件后执行操作++++++++++++*/
        save_log (of, title, buffer, strlen(buffer), log_type);
        /*save_log (stdout, buffer, strlen(buffer), log_type);*/
        i = 0;
        memset (buffer, 0, LOOP_BUFFER_LEN);
        /*}------------符合条件后执行操作------------*/
    }
}

/*{++++++++++++ ++++++++++++*/
/*{*/
/*#include <stdio.h>*/
/*#include <stdlib.h>*/
/*#include <sys/time.h>*/
/*#include <sys/types.h>*/
    /*int    main(void)*/
        /*{*/
            /*fd_set rfds;*/
            /*struct timeval tv;*/
            /*int retval;*/

            /*[> Watch stdin (fd 0) to see when it has input. <]*/
            /*FD_ZERO(&rfds);*/
            /*FD_SET(0, &rfds);*/

            /*[> Wait up to five seconds. <]*/
            /*tv.tv_sec = 5;*/
            /*tv.tv_usec = 0;*/

            /*retval = select(1, &rfds, NULL, NULL, &tv);*/
            /*[> Don’t rely on the value of tv now! <]*/

            /*if (retval == -1)*/
                /*perror("select()");*/
            /*else if (retval)*/
                /*printf("Data is available now.\n");*/
            /*else*/
                /*printf("No data within five seconds.\n");*/

            /*exit(EXIT_SUCCESS);*/
        /*}*/
/*}*/
/*}------------ ------------*/


void debug_mode(cssl_t *serial)
{
    pthread_t keyboard_event_th;
    pthread_create (&keyboard_event_th, NULL, keyboard_event_thread, (void *)serial);//接收键盘
}

#define     DEVICE   "/dev/ttyUSB0"
int main(int argc, char *argv[])
{
    cssl_t *serial = NULL;
    FILE *of = NULL; //日志文件
    char *title = NULL; 

    if (argc != 4)
    {
        usage(argv[0]);
        exit (EXIT_FAILURE);
    }

    cssl_start ();    //串口准备
    serial = cssl_open (argv[1],NULL, 1, 9600, 8, 1, 1);//打开串口
    if ( NULL == serial)
    {
        perror ("open serial");
        exit (EXIT_FAILURE);
    }

    of = fopen (argv[2], "a+"); //打开日志文件
    if (of == NULL) 
    {
        perror ("open file");
        return -1;
    }

    title = argv[3];
    signal(SIGINT, SIG_handle);

    /*init_tty();*/
    /*debug_mode (serial); //键盘调试*/

    loop (serial, of, title); //串口接收主循环

    cssl_close (serial);
    cssl_stop ();
    exit (EXIT_SUCCESS);
}

void SIG_handle(int s)
{
    cssl_stop ();
    /*tcsetattr(tty, TCSANOW, &oldt);*/
    printf ("程序终止！\n");
    exit (EXIT_SUCCESS);
}
